package live.sidian.database.synchronizer.infrastructure.utils;

import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author sidian
 * @date 2021/1/24 10:57
 */
public class BeanUtil extends cn.hutool.core.bean.BeanUtil {
    /**
     * Bean间属性拷贝, 默认忽略null,error
     *
     * @param <T>    目标对象类型
     * @param source 源Bean对象
     * @param tClass 目标Class
     * @return 目标对象
     */
    public static <T> T copyProperties(Object source, Class<T> tClass) {
        return copyProperties(source, tClass, new String[]{});
    }

    /**
     * bean间属性拷贝, 默认忽略null,error
     *
     * @param <T>              目标对象类型
     * @param source           源Bean对象
     * @param tClass           目标Class
     * @param ignoreProperties 忽略的属性
     * @return 目标对象
     */
    public static <T> T copyProperties(Object source, Class<T> tClass, String... ignoreProperties) {
        if (source == null) {
            return null;
        }
        T target = ReflectUtil.newInstanceIfPossible(tClass);
        copyProperties(source, target, CopyOptions.create().ignoreNullValue().ignoreError().setIgnoreProperties(ignoreProperties));
        return target;
    }

    /**
     * 复制Bean对象属性, 默认忽略null, error
     * <br>
     *
     * @param source           源Bean对象
     * @param target           目标Bean对象
     * @param ignoreProperties 要忽略的属性
     */
    public static void copyProperties(Object source, Object target, String... ignoreProperties) {
        copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties).ignoreError().ignoreNullValue());
    }

    /**
     * Bean间属性拷贝, 默认忽略null,error
     *
     * @param <T>    目标对象类型
     * @param source 源Bean对象
     * @param target 目标Class
     * @return 目标对象
     */
    public static <T> T copyProperties(Object source, T target) {
        if (source == null) {
            return null;
        }
        copyProperties(source, target, CopyOptions.create().ignoreNullValue().ignoreError());
        return target;
    }

    @FunctionalInterface
    public interface FieldGetter<T, R> extends java.util.function.Function<T, R>, Serializable {
    }

    public static <T> String getFieldName(FieldGetter<T, Object> consumer) {
        try {
            return doGetFieldName(consumer);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException("字段名获取失败", e);
        }
    }

    private static <T> String doGetFieldName(FieldGetter<T, Object> consumer) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 获取方法名
        Method writeReplace = consumer.getClass().getDeclaredMethod("writeReplace");
        writeReplace.setAccessible(true);
        String methodName = ((SerializedLambda) writeReplace.invoke(consumer)).getImplMethodName();
        // 获取字段名
        if (methodName.startsWith("get")) {
            return StrUtil.lowerFirst(methodName.substring("get".length()));
        } else if (methodName.startsWith("is")) {
            return StrUtil.lowerFirst(methodName.substring("is".length()));
        } else {
            return methodName;
        }
    }

}
